#include "stdafx.h"
#include <iostream>
#include <typeinfo>
using std::cout;
using std::cin;
using std::endl;

#include <string>
using std::string;

#include "Parser.h"
#include "General.h"
#include "FactoryEscenario.h"
#include "Elemento.h"
#include "Sapo.h"
#include "Punto.h"
#include "Carril.h"

#include "Validador.h"

 #ifndef NULL
 #ifdef __cplusplus
 #define NULL    0
 #else
 #define NULL    ((void *)0)
 #endif
 #endif

class Consola
{

public:

//constructor
Consola(void)
{
	string linea("");
	while (linea != "exit")
    {
		cout << ">-->> ";
        std::getline(std::cin, linea);

		if (linea !="") EjecutarComando(linea);
	}
}

//destructor
~Consola(void)
{
}
private:
	
Escenario* escenario;
/*
Ejecuta un comando ingresado en la consola
*/
void EjecutarComando(string linea)
{
	vector<string> tokens;
	Tokenize(linea,tokens," ");

	string comando;
	string param1;
	
	vector<string>::iterator it;
	int i=0;
	for (it = tokens.begin(); it!= tokens.end(); ++it)
	{
		if (i==0) comando = *it;
		else if (i==1) param1 = *it;
		else cout << "Demasiados parametros " << endl;
		i +=1;
	}
	if (comando=="help"){
		cout << "Esta es la ayuda del visor de escenarios\n"
			<< "(Todos los comandos se ingresan en minusculas)\n"
			<< "\n"
			<< " Posibles comandos:\n"
			<< " -show : muestra el escenario cargado.\n"
			<< " -load [path xml]: carga el archivo XML pasado.\n"
			<< " -exit: sale del programa.\n" 
			<< " -BuscarId [Id]: Busca un Id y lo imprime en pantalla"
			<< " -BuscarTag [Tag]: Busca un Tag y lo imprime en pantalla" << endl;

		}else if (comando=="show"){
			ImprimirEscenario(escenario);

		}else if (comando=="load"){
			Parser parser;
			char* param1Char = strdup(param1.c_str());
			parser.parsear(param1Char);
			if (parser.error == ""){
				try{
					free(param1Char);
					bool isValid=false;
					Validador validador(parser.arbolXML);
					NodoXML resultado = validador.validar(isValid);
					if (isValid) escenario = FactoryEscenario::GenerarEscenario(&parser.arbolXML);
					//if (isValid) escenario = FactoryEscenario::GenerarEscenario(&resultado);
					else cout << "La definicion del escenario del XML no es correcta" << endl;
					}catch(runtime_error &error){
						cout << "Error: " << error.what();
					}
			}
			else
			{	Log4Cpp::error(parser.error, "Parser.cpp");
				Log4Cpp::error("No se pudo cargar el nivel", "Parser.cpp" );
			}
					
		}else if (comando=="BuscarId"){
			if (param1 != "")
				BuscarId(param1, escenario);
			else
				cout << "Ingrese un parametro de busqueda\n";
		}else if (comando=="BuscarTag"){
			BuscarTag(param1, escenario);
		}
		else cout << "El comando no es valido, por favor consulta la ayuda (comando: help)"<< endl;
}

/*
Imprime general
*/
void ImprimirGeneral(General* general)
{
    cout << "- Resolucion: " << (*general).GetResolucion() << "\n" << endl;
	cout << "- Color de fondo de elemento: " << (*general).GetColorFondoElem() << "\n" << endl;
	cout << "- Color de fondo de escenario: " << (*general).GetColorFondoEsc() << "\n" << endl;
	cout << "- Color de linea: " << (*general).GetColorLinea() << "\n" << endl;
	cout << "- Textura para elementos: " << (*general).GetIdTextEle() << "\n" << endl;
	cout << "- Textura para escenario: " << (*general).GetIdTextEsc() << "\n" << endl;
}

/*
Imprime el escenario pasado por parametro
*/
void ImprimirEscenario(Escenario* escenario)
{
	cout << "-> ESCENARIO - ID: " << (*escenario).GetId() << "\n" << endl;
	cout << "\n";
	cout << "-> GENERAL" << "\n" << endl;

	General* general=(*escenario).GetGeneral();
	cout << "- Resolucion: " << (*general).GetResolucion() << "\n" << endl;
	cout << "- Color de fondo de elemento: " << (*general).GetColorFondoElem() << "\n" << endl;
	cout << "- Color de fondo de escenario: " << (*general).GetColorFondoEsc() << "\n" << endl;
	cout << "- Color de linea: " << (*general).GetColorLinea() << "\n" << endl;
	cout << "- Textura para elementos: " << (*general).GetIdTextEle() << "\n" << endl;
	cout << "- Textura para escenario: " << (*general).GetIdTextEsc() << "\n" << endl;
	
	cout << "\n";
	
	vector<Elemento*> listaElementos = (*escenario).getListaElementos();
	vector<Elemento*>::iterator itElementos;
	cout << "-> LISTA DE ELEMENTOS\n" << endl;
	for (itElementos=listaElementos.begin(); itElementos!=listaElementos.end(); ++itElementos)
	{
		cout << "- " << (*itElementos)->toString() << endl;
//		cout << "- " << (*itElementos)->getid() << endl;
		cout << "\n";
	}
	cout << "\n";
	cout << "-> LISTA DE TEXTURAS\n" << endl;
	vector<Textura*> listaTexturas = (*escenario).GetListaTexturas();
	vector<Textura*>::iterator itTexturas;
	for (itTexturas = listaTexturas.begin(); itTexturas!=listaTexturas.end(); ++itTexturas )
	{
		cout << "- " << (*itTexturas)->toString() << endl;
		cout << "\n";
	}
}
/*
parsea el comando ingresado
*/
void Tokenize(const string& str,vector<string>& tokens, string del)
{
string delimiters = del;
string::size_type lastPos = str.find_first_not_of(delimiters, 0);
string::size_type pos = str.find_first_of(delimiters, lastPos);
while (string::npos != pos || string::npos != lastPos)
	{
	tokens.push_back(str.substr(lastPos, pos - lastPos));
	lastPos = str.find_first_not_of(delimiters, pos);
	pos = str.find_first_of(delimiters, lastPos);
	}
}

void BuscarTag(string Tag, Escenario *escenario)
{
 bool enctag = false;
 string aux("");
 if ( Tag == "General")
   {
     General *gen = escenario->GetGeneral();
	 ImprimirGeneral(gen);
	 enctag = true;
   }
 if ( Tag == "ListadoDeTexturas" || Tag == "Textura")
   {
	    enctag = true;
	 	vector<Textura*> vText;
		vText = escenario->GetListaTexturas();
		vector<Textura*>::iterator itText;
		for(itText = vText.begin(); itText<vText.end(); itText++)
		{			
				cout << "-------------------------------------------------\n";
				cout << "- " << (*itText)->toString() << endl;
				cout << "\n";
				cout << "-------------------------------------------------";
				cout << "\n";
							
		}
   }

 if ( Tag == "ListadoDeElementos"  )
 {		
	    enctag = true;
 		vector<Elemento*>			vElem = (*escenario).getListaElementos();
		vector<Elemento*>::iterator itElem;
		for (itElem=vElem.begin(); itElem<vElem.end(); ++itElem)
		{
			cout << "-------------------------------------------------\n";
			cout << "- " << (*itElem)->toString() << endl;
			cout << "\n";
			cout << "-------------------------------------------------";
			cout << "\n";
		}
 }
 if ((Tag == "Sapo") || (Tag == "Sumidero") || (Tag == "Carril"))
 {
	    enctag = true;
        vector<Elemento*>			vElem = (*escenario).getListaElementos();
		vector<Elemento*>::iterator itElem;
		for (itElem=vElem.begin(); itElem<vElem.end(); ++itElem)
		{
			aux = typeid(**itElem).name() ;
			aux.erase(0,6);
			if ( Tag == aux ) 
		{
			cout << "-------------------------------------------------\n";
			cout << "- " << (*itElem)->toString() << endl;
			cout << "\n";
			cout << "-------------------------------------------------";
			cout << "\n";
		}
		}
 }
 
 if (enctag == false)
 {
 cout << "El Tag ingresado es invalido, vuelva a intentarlo \n" << endl;
 };

}

int BuscarId(string Id, Escenario *escenario)
{
	//Buscar si la configuracion general tiene ese Id
	bool encontrado = false;
	string aux;
	
	General *gen = escenario->GetGeneral();
	if (gen->GetId() == Id)
	{
		//Id encontrado imprimir atributos de general
		encontrado = true;
		ImprimirGeneral(gen);
	}//Ahora lo busco en la lista de texturas
	else
	{
		vector<Textura*> vText;
		vText = escenario->GetListaTexturas();
		vector<Textura*>::iterator itText;
		for(itText = vText.begin(); itText<vText.end(); itText++)
		{
			if( (*itText)->GetIdTextura() == Id)
			{
				encontrado = true;
				cout << "Textura encontrada:" << Id << "\n"; 
				cout << "- " << (*itText)->toString() << endl;
				cout << "\n";
				cout << "-------------------------------------------------";
				cout << "\n";
				break;
			}
		}
	if( encontrado == false )
	{
		vector<Elemento*>			vElem = (*escenario).getListaElementos();
		vector<Elemento*>::iterator itElem;
		for (itElem=vElem.begin(); itElem<vElem.end(); ++itElem)
		{
			aux = typeid(**itElem).name() ;
			aux.erase(0,6);
			if ( aux == "Carril")
			{
				Carril *carrilAux = dynamic_cast<Carril*>((*itElem));
				vector<Punto*> listaPuntos = carrilAux->getListaDePuntos();
				vector<Punto*>::iterator itPunto;
				for(itPunto = listaPuntos.begin(); itPunto < listaPuntos.end(); itPunto++)
				{
					if ((*itPunto)->GetId() == Id){
						cout << "Punto encontrado:" << Id << "\n"; 
						cout << "- " << (*itPunto)->toString() << endl;
						cout << "\n";
						cout << "-------------------------------------------------";
						cout << "\n";
						return 0;}
				}
			}
			if ( (*itElem)->getid() == Id)
			{
			encontrado = true;
			cout << "Elemento encontrado:" << Id << "\n"; 
			cout << "- " << (*itElem)->toString() << endl;
			cout << "\n";
			cout << "-------------------------------------------------";
			cout << "\n";
			break;
			}
		}
	}
	
	if (encontrado == false)
		cout << "Id no encontrado, ingresar nuevamente.\n" << endl;
	}
}	
};

int main (int argc, char ** argv[])
{
	Consola consola;
	return 0;
}